package com.tyrone.captcha.interceptor;

import com.alibaba.fastjson.JSON;
import com.tyrone.captcha.config.aop.RequestLimit;
import com.tyrone.captcha.entity.Response;
import com.tyrone.captcha.entity.constant.ResponseCode;
import com.tyrone.captcha.util.IpUtil;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * 请求限制拦截器
 *
 * @author xieyl
 * @create 2021/11/8 15:01
 */
@Component
public class RequestLimitInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            RequestLimit requestLimit = method.getAnnotation(RequestLimit.class);
            if (requestLimit == null) {
                return true;
            }
            int requestNumLimit = requestLimit.requestNumLimit();
            int requestTimeLimit = requestLimit.requestTimeLimit();
            String key = IpUtil.getIpAddr(request) + request.getRequestURI();
            String value = (String) redisTemplate.opsForValue().get(key);
            Integer requestNum = null;
            if (value != null && !value.equals("")) {
                requestNum = Integer.valueOf(value);
            }
            if (requestNum == null) {
                redisTemplate.opsForValue().set(key, "1", requestTimeLimit);
            } else if (requestNum < requestNumLimit) {
                Integer num = requestNum + 1;
                redisTemplate.opsForValue().set(key, num.toString(), requestTimeLimit);
            } else {
                return responseInvalidateRequest(response, ResponseCode.FREQUENT_REQUEST, "请求过于频繁");
            }
        }
        return true;
    }

    /**
     * 输出非法请求的响应
     *
     * @param response
     * @param responseCode
     * @param msg
     * @return
     * @throws Exception
     */
    private boolean responseInvalidateRequest(HttpServletResponse response, ResponseCode responseCode, String msg) throws Exception {
        response.setContentType("application/json;;charset=UTF-8");
        Response data = new Response(responseCode, msg != null ? msg : responseCode.getMsg());
        response.getWriter().write(JSON.toJSONString(data));
        return false;
    }
}
